using System;

namespace SharpObjects.Shared.Cleanup
{

    // SAMPLE IMPLEMENTATION

    internal class MyCleanClass : IDisposable, ICleanable
    {
        private CleanupProxy cleanupProxy;

        public MyCleanClass()
        {
            this.cleanupProxy = new CleanupProxy(this);
        }


        #region IDisposable Members

        public void Dispose()
        {
            this.cleanupProxy.DoDispose();
        }

        #endregion

        #region Finalizer

        // must only be implemented if there are unmanaged resources to release
        // implementing the finalizer introduces overhead for garbage collection
        ~MyCleanClass()
        {
            this.cleanupProxy.DoFinalize();
        }

        #endregion Finalizer

        #region ICleanable Members

        // will not be called if the Dispose method is implemented to call cleanupProxy.DoDispose()
        public void ReleaseManagedResources()
        {
            // do release managed resources here
        }

        // will not be called if the destructor (finalizer) is implemented
        public void ReleaseUnmanagedResources()
        {
            // do release unmanaged resources here
        }

        #endregion
    }


    public class CleanupProxy
    {
        private ICleanable cleanable;

        private object syncRoot = new object();

        public CleanupProxy(ICleanable cleanable)
        {
            this.cleanable = cleanable;
        }

        private bool managedCleanedup;

        private void CleanupManagedResources()
        {
            if (!this.managedCleanedup)
            {
                lock (this.syncRoot)
                {
                    if (this.cleanable != null)
                    {
                        this.cleanable.ReleaseManagedResources();
                        this.managedCleanedup = true;
                    }
                }
            }
        }

        private bool unmanagedCleanedup;

        private void CleanupUnmanagedResources()
        {
            if (!this.unmanagedCleanedup)
            {
                lock (this.syncRoot)
                {
                    if (this.cleanable != null)
                    {
                        this.cleanable.ReleaseUnmanagedResources();
                        this.unmanagedCleanedup = true;
                        GC.SuppressFinalize(this);
                    }
                }
            }
        }

        public void DoDispose()
        {
            this.CleanupManagedResources();
            this.CleanupUnmanagedResources();
        }

        public void DoFinalize()
        {
            this.CleanupUnmanagedResources();
        }
    }
}